﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace Pixysoft.Framework.Noebe.MemoryCaches.Core
{
    class CachePagingCommand : IPagingCommand
    {
        ICacheSetting setting;

        IPagingCommand command = null;

        public CachePagingCommand(ICacheSetting setting)
        {
            this.setting = setting;

            INoebeManager manager = SettingHelper.GetManager(setting);

            this.command = manager.PagingCommand;
        }

        public string TableName
        {
            get
            {
                return command.TableName;
            }
            set
            {
                command.TableName = value;
            }
        }

        public string ColumnName
        {
            get
            {
                return command.ColumnName;
            }
            set
            {
                command.ColumnName = value;
            }
        }

        public int PageCapacity
        {
            get
            {
                return command.PageCapacity;
            }
            set
            {
                command.PageCapacity = value;
            }
        }

        public int PageIndex
        {
            get
            {
                return command.PageIndex;
            }
            set
            {
                command.PageIndex = value;
            }
        }

        public bool Reverse
        {
            get
            {
                return command.Reverse;
            }
            set
            {
                command.Reverse = value;
            }
        }

        public string Condition
        {
            get
            {
                return command.Condition;
            }
            set
            {
                command.Condition = value;
            }
        }

        public NoebeParameterCollection Parameters
        {
            get { return command.Parameters; }
        }

        public System.Data.DataTable ExecuteReader()
        {
            //获取需要的参数

            string sqlValue = command.GetSQL();

            string cachekey = StringHelper.CreateCacheKey(command);

            //获取缓存

            if (CacheDataSet.Instance.Contains(setting.SettingName, sqlValue, cachekey))
            {
                return ExecuteReaderFromCache(sqlValue, cachekey);
            }

            return ExecuteReaderToCache(sqlValue, cachekey);
        }

        private DataTable ExecuteReaderToCache(string sqlValue, string cachekey)
        {
            //读取数据库

            DataTable table = command.ExecuteReader();


            //获取缓存的表结构

            DataTable schema = table.Clone();


            //创建缓存

            ICacheDataTable cachetable = null;

            if (CacheDataSet.Instance.Contains(setting.SettingName, sqlValue))
            {
                cachetable = CacheDataSet.Instance.GetCache(setting.SettingName, sqlValue);

                //判断表结构是否一致 

                if (!cachetable.SchemaIsConfirmed(schema))
                {
                    CacheDataSet.Instance.RemoveTable(schema.TableName);

                    cachetable = CacheDataSet.Instance.CreateCache(setting.SettingName, sqlValue, schema, setting.MaxCapacity);
                }
            }
            else
            {
                cachetable = CacheDataSet.Instance.CreateCache(setting.SettingName, sqlValue, schema, setting.MaxCapacity);
            }

            if (table.Rows.Count == 0)
            {
                //10-04-10 null使用默认时间限制

                cachetable.AddNullCache(cachekey, StringHelper.default_cache_nulltimespan);

                //cachetable.AddNullCache(cachekey, setting.TimeSpan);
            }
            else
            {
                switch (setting.CacheMode)
                {
                    case CacheMode.DeepCache:
                        {
                            cachetable.AddDeepCache(cachekey, setting.TimeSpan, table);

                            break;
                        }
                    case CacheMode.ShallowCache:
                    default:
                        {
                            cachetable.AddShallowCache(cachekey, setting.TimeSpan, table);

                            break;
                        }
                }
            }

            return table;
        }

        private DataTable ExecuteReaderFromCache(string sqlValue, string cachekey)
        {
            ICacheDataTable cachetable = CacheDataSet.Instance.GetCache(setting.SettingName, sqlValue);

            DataTable rtable = cachetable.Get(cachekey);

            AsyncExecuteReaderToCacheParameter parameter = new AsyncExecuteReaderToCacheParameter();
            parameter.SqlValue = sqlValue;
            parameter.CacheKey = cachekey;

            //2010-09-26 不使用异步

            if (cachetable.IsOverdued(cachekey))
                AsyncExecuteReaderToCache(parameter);

            //Pixysoft.MultiThread.AsyncInvoker<AsyncExecuteReaderToCacheParameter>.Invoke(AsyncExecuteReaderToCache, parameter);

            return rtable;
        }

        private void AsyncExecuteReaderToCache(AsyncExecuteReaderToCacheParameter parameter)
        {
            string sqlValue = parameter.SqlValue;

            string cachekey = parameter.CacheKey;

            try
            {
                ExecuteReaderToCache(sqlValue, cachekey);
            }
            catch (System.Net.WebException ex) //10-02-11 提高exception的精度
            {
                LoggerHelper.Info("async read data fail.");

                LoggerHelper.Info(ex.Message);
            }
            catch (System.InvalidOperationException ex)// 读取的回复档案出错也会抛异常。
            {
                LoggerHelper.Info("async read data fail.");

                LoggerHelper.Info(ex.Message);
            }
            catch (System.Threading.ThreadAbortException ex)
            {
                LoggerHelper.Info("async read data fail.");

                LoggerHelper.Info(ex.Message);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);
            }
        }

        public void Dispose()
        {
            command.Dispose();
        }

        public string GetSQL()
        {
            return command.GetSQL();
        }

        class AsyncExecuteReaderToCacheParameter
        {
            string sqlValue;
            string cacheKey;
            public string SqlValue
            {
                get { return sqlValue; }
                set { sqlValue = value; }
            }
            public string CacheKey
            {
                get { return cacheKey; }
                set { cacheKey = value; }
            }
        }
    }
}

